home *** CD-ROM | disk | FTP | other *** search
/ Amiga Games Extra 1996 September / Amiga Games Extra CD-ROM 9-1996.iso / userbox / publicdomain / vim-4.2 / src / buffer.c < prev    next >
C/C++ Source or Header  |  1996-06-11  |  38KB  |  1,699 lines

  1. /* vi:set ts=4 sw=4:
  2.  *
  3.  * VIM - Vi IMproved        by Bram Moolenaar
  4.  *
  5.  * Do ":help uganda"  in Vim to read copying and usage conditions.
  6.  * Do ":help credits" in Vim to see a list of people who contributed.
  7.  */
  8.  
  9. /*
  10.  * buffer.c: functions for dealing with the buffer structure
  11.  */
  12.  
  13. /*
  14.  * The buffer list is a double linked list of all buffers.
  15.  * Each buffer can be in one of these states:
  16.  * never loaded: b_neverloaded == TRUE, only the file name is valid
  17.  *   not loaded: b_ml.ml_mfp == NULL, no memfile allocated
  18.  *       hidden: b_nwindows == 0, loaded but not displayed in a window
  19.  *       normal: loaded and displayed in a window
  20.  *
  21.  * Instead of storing file names all over the place, each file name is
  22.  * stored in the buffer list. It can be referenced by a number.
  23.  *
  24.  * The current implementation remembers all file names ever used.
  25.  */
  26.  
  27. #include "vim.h"
  28. #include "globals.h"
  29. #include "proto.h"
  30. #include "option.h"
  31.  
  32. static void        enter_buffer __ARGS((BUF *));
  33. static void        free_buf_options __ARGS((BUF *));
  34. static char_u    *buflist_match __ARGS((regexp *prog, BUF *buf));
  35. static void        buflist_setlnum __ARGS((BUF *, linenr_t));
  36. static linenr_t buflist_findlnum __ARGS((BUF *));
  37. static void        append_arg_number __ARGS((char_u *, int));
  38.  
  39. /*
  40.  * Open current buffer, that is: open the memfile and read the file into memory
  41.  * return FAIL for failure, OK otherwise
  42.  */
  43.      int
  44. open_buffer()
  45. {
  46.     int        retval = OK;
  47.  
  48.     /*
  49.      * The 'readonly' flag is only set when b_neverloaded is being reset.
  50.      * When re-entering the same buffer, it should not change, because the
  51.      * user may have reset the flag by hand.
  52.      */
  53.     if (readonlymode && curbuf->b_filename != NULL && curbuf->b_neverloaded)
  54.         curbuf->b_p_ro = TRUE;
  55.  
  56.     if (ml_open() == FAIL)
  57.     {
  58.         /*
  59.          * There MUST be a memfile, otherwise we can't do anything
  60.          * If we can't create one for the current buffer, take another buffer
  61.          */
  62.         close_buffer(NULL, curbuf, FALSE, FALSE);
  63.         for (curbuf = firstbuf; curbuf != NULL; curbuf = curbuf->b_next)
  64.             if (curbuf->b_ml.ml_mfp != NULL)
  65.                 break;
  66.         /*
  67.          * if there is no memfile at all, exit
  68.          * This is OK, since there are no changes to loose.
  69.          */
  70.         if (curbuf == NULL)
  71.         {
  72.             EMSG("Cannot allocate buffer, exiting...");
  73.             getout(2);
  74.         }
  75.         EMSG("Cannot allocate buffer, using other one...");
  76.         enter_buffer(curbuf);
  77.         return FAIL;
  78.     }
  79.     if (curbuf->b_filename != NULL)
  80.         retval = readfile(curbuf->b_filename, curbuf->b_sfilename,
  81.                               (linenr_t)0, TRUE, (linenr_t)0, MAXLNUM, FALSE);
  82.     else
  83.     {
  84.         MSG("Empty Buffer");
  85.         msg_col = 0;
  86.         msg_didout = FALSE;        /* overwrite this message whenever you like */
  87.     }
  88.  
  89.     /* if first time loading this buffer, init chartab */
  90.     if (curbuf->b_neverloaded)
  91.         init_chartab();
  92.  
  93.     /*
  94.      * Reset the Changed flag first, autocmds may change the buffer.
  95.      * Apply the automatic commands, before processing the modelines.
  96.      * So the modelines have priority over auto commands.
  97.      */
  98.     if (retval != FAIL)
  99.         UNCHANGED(curbuf);
  100.  
  101. #ifdef AUTOCMD
  102.     apply_autocmds(EVENT_BUFENTER, NULL, NULL);
  103. #endif
  104.  
  105.     if (retval != FAIL)
  106.     {
  107.         do_modelines();
  108.         curbuf->b_neverloaded = FALSE;
  109.     }
  110.  
  111.     return retval;
  112. }
  113.  
  114. /*
  115.  * Close the link to a buffer. If "free_buf" is TRUE free the buffer if it
  116.  * becomes unreferenced. The caller should get a new buffer very soon!
  117.  * if 'del_buf' is TRUE, remove the buffer from the buffer list.
  118.  */
  119.     void
  120. close_buffer(win, buf, free_buf, del_buf)
  121.     WIN        *win;            /* if not NULL, set b_last_cursor */
  122.     BUF        *buf;
  123.     int        free_buf;
  124.     int        del_buf;
  125. {
  126.     if (buf->b_nwindows > 0)
  127.         --buf->b_nwindows;
  128.     if (buf->b_nwindows == 0 && win != NULL)
  129.         set_last_cursor(win);    /* may set b_last_cursor */
  130.     if (buf->b_nwindows > 0 || !free_buf)
  131.     {
  132.         if (buf == curbuf)
  133.             u_sync();        /* sync undo before going to another buffer */
  134.         return;
  135.     }
  136.  
  137.     buf_freeall(buf);        /* free all things allocated for this buffer */
  138.     /*
  139.      * If there is no file name, remove the buffer from the list
  140.      */
  141.     if (buf->b_filename == NULL || del_buf)
  142.     {
  143.         vim_free(buf->b_filename);
  144.         vim_free(buf->b_sfilename);
  145.         if (buf->b_prev == NULL)
  146.             firstbuf = buf->b_next;
  147.         else
  148.             buf->b_prev->b_next = buf->b_next;
  149.         if (buf->b_next == NULL)
  150.             lastbuf = buf->b_prev;
  151.         else
  152.             buf->b_next->b_prev = buf->b_prev;
  153.         free_buf_options(buf);
  154.     }
  155.     else
  156.         buf_clear(buf);
  157. }
  158.  
  159. /*
  160.  * buf_clear() - make buffer empty
  161.  */
  162.     void
  163. buf_clear(buf)
  164.     BUF        *buf;
  165. {
  166.     buf->b_ml.ml_line_count = 1;
  167.     buf->b_changed = FALSE;
  168. #ifndef SHORT_FNAME
  169.     buf->b_shortname = FALSE;
  170. #endif
  171.     buf->b_p_eol = TRUE;
  172.     buf->b_ml.ml_mfp = NULL;
  173.     buf->b_ml.ml_flags = ML_EMPTY;                /* empty buffer */
  174. }
  175.  
  176. /*
  177.  * buf_freeall() - free all things allocated for the buffer
  178.  */
  179.     void
  180. buf_freeall(buf)
  181.     BUF        *buf;
  182. {
  183.     u_blockfree(buf);                /* free the memory allocated for undo */
  184.     ml_close(buf, TRUE);            /* close and delete the memline/memfile */
  185.     buf->b_ml.ml_line_count = 0;    /* no lines in buffer */
  186.     u_clearall(buf);                /* reset all undo information */
  187. }
  188.  
  189. /*
  190.  * do_bufdel() - delete or unload buffer(s)
  191.  *
  192.  * addr_count == 0:    ":bdel" - delete current buffer
  193.  * addr_count == 1: ":N bdel" or ":bdel N [N ..] - first delete
  194.  *                    buffer "end_bnr", then any other arguments.
  195.  * addr_count == 2: ":N,N bdel" - delete buffers in range
  196.  *
  197.  * command can be DOBUF_UNLOAD (":bunload") or DOBUF_DEL (":bdel")
  198.  *
  199.  * Returns error message or NULL
  200.  */
  201.     char_u *
  202. do_bufdel(command, arg, addr_count, start_bnr, end_bnr, forceit)
  203.     int        command;
  204.     char_u    *arg;        /* pointer to extra arguments */
  205.     int        addr_count;
  206.     int        start_bnr;    /* first buffer number in a range */
  207.     int        end_bnr;    /* buffer number or last buffer number in a range */
  208.     int        forceit;
  209. {
  210.     int        do_current = 0;        /* delete current buffer? */
  211.     int        deleted = 0;        /* number of buffers deleted */
  212.     char_u    *errormsg = NULL;    /* return value */
  213.     int        bnr;                /* buffer number */
  214.     char_u    *p;
  215.  
  216.     if (addr_count == 0)
  217.         (void)do_buffer(command, DOBUF_CURRENT, FORWARD, 0, forceit);
  218.     else
  219.     {
  220.         if (addr_count == 2)
  221.         {
  222.             if (*arg)            /* both range and argument is not allowed */
  223.                 return e_trailing;
  224.             bnr = start_bnr;
  225.         }
  226.         else    /* addr_count == 1 */
  227.             bnr = end_bnr;
  228.  
  229.         for ( ;!got_int; mch_breakcheck())
  230.         {
  231.             /*
  232.              * delete the current buffer last, otherwise when the
  233.              * current buffer is deleted, the next buffer becomes
  234.              * the current one and will be loaded, which may then
  235.              * also be deleted, etc.
  236.              */
  237.             if (bnr == curbuf->b_fnum)
  238.                 do_current = bnr;
  239.             else if (do_buffer(command, DOBUF_FIRST, FORWARD, (int)bnr,
  240.                     forceit) == OK)
  241.                 ++deleted;
  242.  
  243.             /*
  244.              * find next buffer number to delete/unload
  245.              */
  246.             if (addr_count == 2)
  247.             {
  248.                 if (++bnr > end_bnr)
  249.                     break;
  250.             }
  251.             else    /* addr_count == 1 */
  252.             {
  253.                 arg = skipwhite(arg);
  254.                 if (*arg == NUL)
  255.                     break;
  256.                 if (!isdigit(*arg))
  257.                 {
  258.                     p = skiptowhite_esc(arg);
  259.                     bnr = buflist_findpat(arg, p);
  260.                     if (bnr < 0)            /* failed */
  261.                         break;
  262.                     arg = p;
  263.                 }
  264.                 else
  265.                     bnr = getdigits(&arg);
  266.             }
  267.         }
  268.         if (!got_int && do_current && do_buffer(command, DOBUF_FIRST,
  269.                 FORWARD, do_current, forceit) == OK)
  270.             ++deleted;
  271.  
  272.         if (deleted == 0)
  273.         {
  274.             sprintf((char *)IObuff, "No buffers were %s",
  275.                     command == DOBUF_UNLOAD ? "unloaded" : "deleted");
  276.             errormsg = IObuff;
  277.         }
  278.         else
  279.             smsg((char_u *)"%d buffer%s %s", deleted,
  280.                     plural((long)deleted),
  281.                     command == DOBUF_UNLOAD ? "unloaded" : "deleted");
  282.     }
  283.  
  284.     return errormsg;
  285. }
  286.  
  287. /*
  288.  * Implementation of the command for the buffer list
  289.  *
  290.  * action == DOBUF_GOTO        go to specified buffer
  291.  * action == DOBUF_SPLIT    split window and go to specified buffer
  292.  * action == DOBUF_UNLOAD    unload specified buffer(s)
  293.  * action == DOBUF_DEL        delete specified buffer(s)
  294.  *
  295.  * start == DOBUF_CURRENT    go to "count" buffer from current buffer
  296.  * start == DOBUF_FIRST        go to "count" buffer from first buffer
  297.  * start == DOBUF_LAST        go to "count" buffer from last buffer
  298.  * start == DOBUF_MOD        go to "count" modified buffer from current buffer
  299.  *
  300.  * Return FAIL or OK.
  301.  */
  302.     int
  303. do_buffer(action, start, dir, count, forceit)
  304.     int        action;
  305.     int        start;
  306.     int        dir;        /* FORWARD or BACKWARD */
  307.     int        count;        /* buffer number or number of buffers */
  308.     int        forceit;    /* TRUE for :bdelete! */
  309. {
  310.     BUF        *buf;
  311.     BUF        *delbuf;
  312.     int        retval;
  313.  
  314.     switch (start)
  315.     {
  316.         case DOBUF_FIRST:    buf = firstbuf;    break;
  317.         case DOBUF_LAST:    buf = lastbuf;    break;
  318.         default:            buf = curbuf;    break;
  319.     }
  320.     if (start == DOBUF_MOD)            /* find next modified buffer */
  321.     {
  322.         while (count-- > 0)
  323.         {
  324.             do
  325.             {
  326.                 buf = buf->b_next;
  327.                 if (buf == NULL)
  328.                     buf = firstbuf;
  329.             }
  330.             while (buf != curbuf && !buf->b_changed);
  331.         }
  332.         if (!buf->b_changed)
  333.         {
  334.             EMSG("No modified buffer found");
  335.             return FAIL;
  336.         }
  337.     }
  338.     else if (start == DOBUF_FIRST && count)    /* find specified buffer number */
  339.     {
  340.         while (buf != NULL && buf->b_fnum != count)
  341.             buf = buf->b_next;
  342.     }
  343.     else
  344.     {
  345.         while (count-- > 0)
  346.         {
  347.             if (dir == FORWARD)
  348.             {
  349.                 buf = buf->b_next;
  350.                 if (buf == NULL)
  351.                     buf = firstbuf;
  352.             }
  353.             else
  354.             {
  355.                 buf = buf->b_prev;
  356.                 if (buf == NULL)
  357.                     buf = lastbuf;
  358.             }
  359.         }
  360.     }
  361.  
  362.     if (buf == NULL)        /* could not find it */
  363.     {
  364.         if (start == DOBUF_FIRST)
  365.         {
  366.                                             /* don't warn when deleting */
  367.             if (action != DOBUF_UNLOAD && action != DOBUF_DEL)
  368.                 EMSGN("Cannot go to buffer %ld", count);
  369.         }
  370.         else if (dir == FORWARD)
  371.             EMSG("Cannot go beyond last buffer");
  372.         else
  373.             EMSG("Cannot go before first buffer");
  374.         return FAIL;
  375.     }
  376.  
  377.     /*
  378.      * delete buffer buf from memory and/or the list
  379.      */
  380.     if (action == DOBUF_UNLOAD || action == DOBUF_DEL)
  381.     {
  382.         if (!forceit && buf->b_changed)
  383.         {
  384.             EMSGN("No write since last change for buffer %ld (use ! to override)",
  385.                         buf->b_fnum);
  386.             return FAIL;
  387.         }
  388.  
  389.         /*
  390.          * If deleting last buffer, make it empty.
  391.          * The last buffer cannot be unloaded.
  392.          */
  393.         if (firstbuf->b_next == NULL)
  394.         {
  395.             if (action == DOBUF_UNLOAD)
  396.             {
  397.                 EMSG("Cannot unload last buffer");
  398.                 return FAIL;
  399.             }
  400.             /* Close any other windows on this buffer */
  401.             close_others(FALSE);
  402.             buf = curbuf;
  403.             setpcmark();
  404.             retval = do_ecmd(0, NULL, NULL, NULL, FALSE, (linenr_t)1, FALSE);
  405.             /*
  406.              * The do_ecmd() may create a new buffer, then we have to delete
  407.              * the old one.  But do_ecmd() may have done that already, check
  408.              * if the buffer still exists (it will be the first or second in
  409.              * the buffer list).
  410.              */
  411.             if (buf != curbuf && (buf == firstbuf || buf == firstbuf->b_next))
  412.                 close_buffer(NULL, buf, TRUE, TRUE);
  413.             return retval;
  414.         }
  415.  
  416.         /*
  417.          * If the deleted buffer is the current one, close the current window
  418.          * (unless it's the only window).
  419.          */
  420.         while (buf == curbuf && firstwin != lastwin)
  421.             close_window(curwin, FALSE);
  422.  
  423.         /*
  424.          * If the buffer to be deleted is not current one, delete it here.
  425.          */
  426.         if (buf != curbuf)
  427.         {
  428.             close_windows(buf);
  429.             close_buffer(NULL, buf, TRUE, action == DOBUF_DEL);
  430.             return OK;
  431.         }
  432.  
  433.         /*
  434.          * Deleting the current buffer: Need to find another buffer to go to.
  435.          * There must be another, otherwise it would have been handled above.
  436.          */
  437.         if (curbuf->b_next != NULL)
  438.             buf = curbuf->b_next;
  439.         else
  440.             buf = curbuf->b_prev;
  441.     }
  442.  
  443.     /*
  444.      * make buf current buffer
  445.      */
  446.     setpcmark();
  447.     if (action == DOBUF_SPLIT)        /* split window first */
  448.     {
  449.         if (win_split(0, FALSE) == FAIL)
  450.             return FAIL;
  451.     }
  452.     curwin->w_alt_fnum = curbuf->b_fnum; /* remember alternate file */
  453.     buflist_altlnum();                     /* remember curpos.lnum */
  454.  
  455. #ifdef AUTOCMD
  456.     apply_autocmds(EVENT_BUFLEAVE, NULL, NULL);
  457. #endif
  458.     delbuf = curbuf;        /* close_windows() may change curbuf */
  459.     if (action == DOBUF_UNLOAD || action == DOBUF_DEL)
  460.         close_windows(curbuf);
  461.     close_buffer(NULL, delbuf, action == DOBUF_UNLOAD || action == DOBUF_DEL,
  462.                                                          action == DOBUF_DEL);
  463.     enter_buffer(buf);
  464.     return OK;
  465. }
  466.  
  467. /*
  468.  * enter a new current buffer.
  469.  * (old curbuf must have been freed already)
  470.  */
  471.     static void
  472. enter_buffer(buf)
  473.     BUF        *buf;
  474. {
  475.     buf_copy_options(curbuf, buf, TRUE);
  476.     curwin->w_buffer = buf;
  477.     curbuf = buf;
  478.     ++curbuf->b_nwindows;
  479.     if (curbuf->b_ml.ml_mfp == NULL)    /* need to load the file */
  480.         open_buffer();
  481.     else
  482.     {
  483.         need_fileinfo = TRUE;            /* display file info after redraw */
  484.         buf_check_timestamp(curbuf);    /* check if file has changed */
  485. #ifdef AUTOCMD
  486.         apply_autocmds(EVENT_BUFENTER, NULL, NULL);
  487. #endif
  488.     }
  489.     buflist_getlnum();                    /* restore curpos.lnum */
  490.     check_arg_idx();                    /* check for valid arg_idx */
  491.     maketitle();
  492.     scroll_cursor_halfway(FALSE);        /* redisplay at correct position */
  493.     updateScreen(NOT_VALID);
  494. }
  495.  
  496. /*
  497.  * functions for dealing with the buffer list
  498.  */
  499.  
  500. /*
  501.  * Add a file name to the buffer list. Return a pointer to the buffer.
  502.  * If the same file name already exists return a pointer to that buffer.
  503.  * If it does not exist, or if fname == NULL, a new entry is created.
  504.  * If use_curbuf is TRUE, may use current buffer.
  505.  * This is the ONLY way to create a new buffer.
  506.  */
  507.     BUF *
  508. buflist_new(fname, sfname, lnum, use_curbuf)
  509.     char_u        *fname;
  510.     char_u        *sfname;
  511.     linenr_t    lnum;
  512.     int            use_curbuf;
  513. {
  514.     static int    top_file_num = 1;            /* highest file number */
  515.     BUF            *buf;
  516.  
  517.     fname_expand(&fname, &sfname);
  518.  
  519. /*
  520.  * If file name already exists in the list, update the entry
  521.  */
  522.     if (fname != NULL && (buf = buflist_findname(fname)) != NULL)
  523.     {
  524.         if (lnum != 0)
  525.             buflist_setlnum(buf, lnum);
  526.         /* copy the options now, if 'cpo' doesn't have 's' and not done
  527.          * already */
  528.         buf_copy_options(curbuf, buf, FALSE);
  529.         return buf;
  530.     }
  531.  
  532. /*
  533.  * If the current buffer has no name and no contents, use the current buffer.
  534.  * Otherwise: Need to allocate a new buffer structure.
  535.  *
  536.  * This is the ONLY place where a new buffer structure is allocated!
  537.  */
  538.     if (use_curbuf && curbuf != NULL && curbuf->b_filename == NULL &&
  539.                 curbuf->b_nwindows <= 1 &&
  540.                 (curbuf->b_ml.ml_mfp == NULL || bufempty()))
  541.         buf = curbuf;
  542.     else
  543.     {
  544.         buf = (BUF *)alloc((unsigned)sizeof(BUF));
  545.         if (buf == NULL)
  546.             return NULL;
  547.         (void)vim_memset(buf, 0, sizeof(BUF));
  548.     }
  549.  
  550.     if (fname != NULL)
  551.     {
  552.         buf->b_filename = strsave(fname);
  553.         buf->b_sfilename = strsave(sfname);
  554.     }
  555.     if (buf->b_winlnum == NULL)
  556.         buf->b_winlnum = (WINLNUM *)alloc((unsigned)sizeof(WINLNUM));
  557.     if ((fname != NULL && (buf->b_filename == NULL ||
  558.                          buf->b_sfilename == NULL)) || buf->b_winlnum == NULL)
  559.     {
  560.         vim_free(buf->b_filename);
  561.         buf->b_filename = NULL;
  562.         vim_free(buf->b_sfilename);
  563.         buf->b_sfilename = NULL;
  564.         if (buf != curbuf)
  565.         {
  566.             vim_free(buf->b_winlnum);
  567.             free_buf_options(buf);
  568.         }
  569.         return NULL;
  570.     }
  571.  
  572.     if (buf == curbuf)
  573.     {
  574.         buf_freeall(buf);        /* free all things allocated for this buffer */
  575.         buf->b_nwindows = 0;
  576.     }
  577.     else
  578.     {
  579.         /*
  580.          * Copy the options from the current buffer.
  581.          */
  582.         buf_copy_options(curbuf, buf, FALSE);
  583.  
  584.         /*
  585.          * put new buffer at the end of the buffer list
  586.          */
  587.         buf->b_next = NULL;
  588.         if (firstbuf == NULL)            /* buffer list is empty */
  589.         {
  590.             buf->b_prev = NULL;
  591.             firstbuf = buf;
  592.         }
  593.         else                            /* append new buffer at end of list */
  594.         {
  595.             lastbuf->b_next = buf;
  596.             buf->b_prev = lastbuf;
  597.         }
  598.         lastbuf = buf;
  599.  
  600.         buf->b_fnum = top_file_num++;
  601.         if (top_file_num < 0)            /* wrap around (may cause duplicates) */
  602.         {
  603.             EMSG("Warning: List of file names overflow");
  604.             mch_delay(3000L, TRUE);        /* make sure it is noticed */
  605.             top_file_num = 1;
  606.         }
  607.  
  608.         buf->b_winlnum->wl_lnum = lnum;
  609.         buf->b_winlnum->wl_next = NULL;
  610.         buf->b_winlnum->wl_prev = NULL;
  611.         buf->b_winlnum->wl_win = curwin;
  612.     }
  613.  
  614.     if (did_cd)
  615.         buf->b_xfilename = buf->b_filename;
  616.     else
  617.         buf->b_xfilename = buf->b_sfilename;
  618.     buf->b_u_synced = TRUE;
  619.     buf->b_neverloaded = TRUE;
  620.     buf_clear(buf);
  621.     clrallmarks(buf);                /* clear marks */
  622.     fmarks_check_names(buf);        /* check file marks for this file */
  623.  
  624.     return buf;
  625. }
  626.  
  627. /*
  628.  * Free the memory for a BUF structure and its options
  629.  */
  630.     static void
  631. free_buf_options(buf)
  632.     BUF        *buf;
  633. {
  634.     free_string_option(buf->b_p_fo);
  635.     free_string_option(buf->b_p_isk);
  636.     free_string_option(buf->b_p_com);
  637. #ifdef CINDENT
  638.     free_string_option(buf->b_p_cink);
  639.     free_string_option(buf->b_p_cino);
  640. #endif
  641. #if defined(CINDENT) || defined(SMARTINDENT)
  642.     free_string_option(buf->b_p_cinw);
  643. #endif
  644.     vim_free(buf);
  645. }
  646.  
  647. /*
  648.  * get alternate file n
  649.  * set linenr to lnum or altlnum if lnum == 0
  650.  * if (options & GETF_SETMARK) call setpcmark()
  651.  * if (options & GETF_ALT) we are jumping to an alternate file.
  652.  *
  653.  * return FAIL for failure, OK for success
  654.  */
  655.     int
  656. buflist_getfile(n, lnum, options)
  657.     int            n;
  658.     linenr_t    lnum;
  659.     int            options;
  660. {
  661.     BUF        *buf;
  662.  
  663.     buf = buflist_findnr(n);
  664.     if (buf == NULL)
  665.     {
  666.         if ((options & GETF_ALT) && n == 0)
  667.             emsg(e_noalt);
  668.         else
  669.             EMSGN("buffer %ld not found", n);
  670.         return FAIL;
  671.     }
  672.  
  673.     /* if alternate file is the current buffer, nothing to do */
  674.     if (buf == curbuf)
  675.         return OK;
  676.  
  677.     /* altlnum may be changed by getfile(), get it now */
  678.     if (lnum == 0)
  679.         lnum = buflist_findlnum(buf);
  680.     ++RedrawingDisabled;
  681.     if (getfile(buf->b_fnum, NULL, NULL, (options & GETF_SETMARK), lnum) <= 0)
  682.     {
  683.         --RedrawingDisabled;
  684.         return OK;
  685.     }
  686.     --RedrawingDisabled;
  687.     return FAIL;
  688. }
  689.  
  690. /*
  691.  * go to the last know line number for the current buffer
  692.  */
  693.     void
  694. buflist_getlnum()
  695. {
  696.     linenr_t    lnum;
  697.  
  698.     curwin->w_cursor.lnum = 1;
  699.     curwin->w_cursor.col = 0;
  700.     lnum = buflist_findlnum(curbuf);
  701.     if (lnum != 0 && lnum <= curbuf->b_ml.ml_line_count)
  702.         curwin->w_cursor.lnum = lnum;
  703. }
  704.  
  705. /*
  706.  * find file in buffer list by name (it has to be for the current window)
  707.  * 'fname' must have a full path.
  708.  */
  709.     BUF *
  710. buflist_findname(fname)
  711.     char_u        *fname;
  712. {
  713.     BUF            *buf;
  714.  
  715.     for (buf = firstbuf; buf != NULL; buf = buf->b_next)
  716.         if (buf->b_filename != NULL && fnamecmp(fname, buf->b_filename) == 0)
  717.             return (buf);
  718.     return NULL;
  719. }
  720.  
  721. /*
  722.  * Find file in buffer list by a regexppattern.
  723.  * Return fnum of the found buffer, < 0 for error.
  724.  */
  725.     int
  726. buflist_findpat(pattern, pattern_end)
  727.     char_u        *pattern;
  728.     char_u        *pattern_end;        /* pointer to first char after pattern */
  729. {
  730.     BUF            *buf;
  731.     regexp        *prog;
  732.     int            fnum = -1;
  733.     char_u        *pat;
  734.     char_u        *match;
  735.     int            attempt;
  736.     char_u        *p;
  737.  
  738.     if (pattern_end == pattern + 1 && (*pattern == '%' || *pattern == '#'))
  739.     {
  740.         if (*pattern == '%')
  741.             fnum = curbuf->b_fnum;
  742.         else
  743.             fnum = curwin->w_alt_fnum;
  744.     }
  745.  
  746.     /*
  747.      * Try four ways of matching:
  748.      * attempt == 0: without '^' or '$' (at any position)
  749.      * attempt == 1: with '^' at start (only at postion 0)
  750.      * attempt == 2: with '$' at end (only match at end)
  751.      * attempt == 3: with '^' at start and '$' at end (only full match)
  752.      */
  753.     else for (attempt = 0; attempt <= 3; ++attempt)
  754.     {
  755.         /* may add '^' and '$' */
  756.         pat = file_pat_to_reg_pat(pattern, pattern_end, NULL);
  757.         if (pat == NULL)
  758.             return -1;
  759.         if (attempt < 2)
  760.         {
  761.             p = pat + STRLEN(pat) - 1;
  762.             if (p > pat && *p == '$')                /* remove '$' */
  763.                 *p = NUL;
  764.         }
  765.         p = pat;
  766.         if (*p == '^' && !(attempt & 1))            /* remove '^' */
  767.             ++p;
  768.         prog = vim_regcomp(p);
  769.         vim_free(pat);
  770.         if (prog == NULL)
  771.             return -1;
  772.  
  773.         for (buf = firstbuf; buf != NULL; buf = buf->b_next)
  774.         {
  775.             match = buflist_match(prog, buf);
  776.             if (match != NULL)
  777.             {
  778.                 if (fnum >= 0)            /* already found a match */
  779.                 {
  780.                     fnum = -2;
  781.                     break;
  782.                 }
  783.                 fnum = buf->b_fnum;        /* remember first match */
  784.             }
  785.         }
  786.         vim_free(prog);
  787.         if (fnum >= 0)                    /* found one match */
  788.             break;
  789.     }
  790.  
  791.     if (fnum == -2)
  792.         EMSG2("More than one match for %s", pattern);
  793.     if (fnum < 1)
  794.         EMSG2("No matching buffer for %s", pattern);
  795.     return fnum;
  796. }
  797.  
  798. /*
  799.  * Find all buffer names that match.
  800.  * For command line expansion of ":buf" and ":sbuf".
  801.  * Return OK if matches found, FAIL otherwise.
  802.  */
  803.     int
  804. ExpandBufnames(pat, num_file, file, options)
  805.     char_u        *pat;
  806.     int            *num_file;
  807.     char_u        ***file;
  808.     int            options;
  809. {
  810.     int            count = 0;
  811.     BUF            *buf;
  812.     int            round;
  813.     char_u        *p;
  814.     int            attempt;
  815.     regexp        *prog;
  816.  
  817.     *num_file = 0;                    /* return values in case of FAIL */
  818.     *file = NULL;
  819.  
  820.     /*
  821.      * attempt == 1: try match with    '^', match at start
  822.      * attempt == 2: try match without '^', match anywhere
  823.      */
  824.     for (attempt = 1; attempt <= 2; ++attempt)
  825.     {
  826.         if (attempt == 2)
  827.         {
  828.             if (*pat != '^')        /* there's no '^', no need to try again */
  829.                 break;
  830.             ++pat;                    /* skip the '^' */
  831.         }
  832.         prog = vim_regcomp(pat);
  833.         if (prog == NULL)
  834.             return FAIL;
  835.  
  836.         /*
  837.          * round == 1: Count the matches.
  838.          * round == 2: Build the array to keep the matches.
  839.          */
  840.         for (round = 1; round <= 2; ++round)
  841.         {
  842.             count = 0;
  843.             for (buf = firstbuf; buf != NULL; buf = buf->b_next)
  844.             {
  845.                 p = buflist_match(prog, buf);
  846.                 if (p != NULL)
  847.                 {
  848.                     if (round == 1)
  849.                         ++count;
  850.                     else
  851.                     {
  852.                         if (options & WILD_HOME_REPLACE)
  853.                             p = home_replace_save(buf, p);
  854.                         else
  855.                             p = strsave(p);
  856.                         (*file)[count++] = p;
  857.                     }
  858.                 }
  859.             }
  860.             if (count == 0)        /* no match found, break here */
  861.                 break;
  862.             if (round == 1)
  863.             {
  864.                 *file = (char_u **)alloc((unsigned)(count * sizeof(char_u *)));
  865.                 if (*file == NULL)
  866.                 {
  867.                     vim_free(prog);
  868.                     return FAIL;
  869.                 }
  870.             }
  871.         }
  872.         vim_free(prog);
  873.         if (count)                /* match(es) found, break here */
  874.             break;
  875.     }
  876.  
  877.     *num_file = count;
  878.     return (count == 0 ? FAIL : OK);
  879. }
  880.  
  881. /*
  882.  * Check for a match on the file name for buffer "buf" with regex prog "prog".
  883.  */
  884.     static char_u *
  885. buflist_match(prog, buf)
  886.     regexp        *prog;
  887.     BUF            *buf;
  888. {
  889.     char_u    *match = NULL;
  890.  
  891.     if (buf->b_sfilename != NULL &&
  892.                                vim_regexec(prog, buf->b_sfilename, TRUE) != 0)
  893.         match = buf->b_sfilename;
  894.     else if (buf->b_filename != NULL)
  895.     {
  896.         if (vim_regexec(prog, buf->b_filename, TRUE) != 0)
  897.             match = buf->b_filename;
  898.         else
  899.         {
  900.             home_replace(NULL, buf->b_filename, NameBuff, MAXPATHL);
  901.             if (vim_regexec(prog, NameBuff, TRUE) != 0)
  902.                 match = buf->b_filename;
  903.         }
  904.     }
  905.     return match;
  906. }
  907.  
  908. /*
  909.  * find file in buffer name list by number
  910.  */
  911.     BUF    *
  912. buflist_findnr(nr)
  913.     int            nr;
  914. {
  915.     BUF            *buf;
  916.  
  917.     if (nr == 0)
  918.         nr = curwin->w_alt_fnum;
  919.     for (buf = firstbuf; buf != NULL; buf = buf->b_next)
  920.         if (buf->b_fnum == nr)
  921.             return (buf);
  922.     return NULL;
  923. }
  924.  
  925. /*
  926.  * get name of file 'n' in the buffer list
  927.  */
  928.      char_u *
  929. buflist_nr2name(n, fullname, helptail)
  930.     int n;
  931.     int fullname;
  932.     int helptail;            /* for help buffers return tail only */
  933. {
  934.     BUF        *buf;
  935.     char_u    *fname;
  936.  
  937.     buf = buflist_findnr(n);
  938.     if (buf == NULL)
  939.         return NULL;
  940.     if (fullname)
  941.         fname = buf->b_filename;
  942.     else
  943.         fname = buf->b_xfilename;
  944.     home_replace(helptail ? buf : NULL, fname, NameBuff, MAXPATHL);
  945.     return NameBuff;
  946. }
  947.  
  948. /*
  949.  * set the lnum for the buffer 'buf' and the current window
  950.  */
  951.     static void
  952. buflist_setlnum(buf, lnum)
  953.     BUF            *buf;
  954.     linenr_t    lnum;
  955. {
  956.     WINLNUM        *wlp;
  957.     
  958.     for (wlp = buf->b_winlnum; wlp != NULL; wlp = wlp->wl_next)
  959.         if (wlp->wl_win == curwin)
  960.             break;
  961.     if (wlp == NULL)            /* make new entry */
  962.     {
  963.         wlp = (WINLNUM *)alloc((unsigned)sizeof(WINLNUM));
  964.         if (wlp == NULL)
  965.             return;
  966.         wlp->wl_win = curwin;
  967.     }
  968.     else                        /* remove entry from list */
  969.     {
  970.         if (wlp->wl_prev)
  971.             wlp->wl_prev->wl_next = wlp->wl_next;
  972.         else
  973.             buf->b_winlnum = wlp->wl_next;
  974.         if (wlp->wl_next)
  975.             wlp->wl_next->wl_prev = wlp->wl_prev;
  976.     }
  977.     wlp->wl_lnum = lnum;
  978. /*
  979.  * insert entry in front of the list
  980.  */
  981.     wlp->wl_next = buf->b_winlnum;
  982.     buf->b_winlnum = wlp;
  983.     wlp->wl_prev = NULL;
  984.     if (wlp->wl_next)
  985.         wlp->wl_next->wl_prev = wlp;
  986.  
  987.     return;
  988. }
  989.  
  990. /*
  991.  * find the lnum for the buffer 'buf' for the current window
  992.  */
  993.     static linenr_t
  994. buflist_findlnum(buf)
  995.     BUF        *buf;
  996. {
  997.     WINLNUM     *wlp;
  998.  
  999.     for (wlp = buf->b_winlnum; wlp != NULL; wlp = wlp->wl_next)
  1000.         if (wlp->wl_win == curwin)
  1001.             break;
  1002.  
  1003.     if (wlp == NULL)        /* if no lnum for curwin, use the first in the list */
  1004.         wlp = buf->b_winlnum;
  1005.  
  1006.     if (wlp)
  1007.         return wlp->wl_lnum;
  1008.     else
  1009.         return (linenr_t)1;
  1010. }
  1011.  
  1012. /*
  1013.  * list all know file names (for :files and :buffers command)
  1014.  */
  1015.     void
  1016. buflist_list()
  1017. {
  1018.     BUF            *buf;
  1019.     int            len;
  1020.  
  1021.     for (buf = firstbuf; buf != NULL && !got_int; buf = buf->b_next)
  1022.     {
  1023.         msg_outchar('\n');
  1024.         if (buf->b_xfilename == NULL)
  1025.             STRCPY(NameBuff, "No File");
  1026.         else
  1027.             /* careful: home_replace calls vim_getenv(), which uses IObuff! */
  1028.             home_replace(buf, buf->b_xfilename, NameBuff, MAXPATHL);
  1029.  
  1030.         sprintf((char *)IObuff, "%3d %c%c%c \"",
  1031.                 buf->b_fnum,
  1032.                 buf == curbuf ? '%' :
  1033.                         (curwin->w_alt_fnum == buf->b_fnum ? '#' : ' '),
  1034.                 buf->b_ml.ml_mfp == NULL ? '-' :
  1035.                         (buf->b_nwindows == 0 ? 'h' : ' '),
  1036.                 buf->b_changed ? '+' : ' ');
  1037.  
  1038.         len = STRLEN(IObuff);
  1039.         STRNCPY(IObuff + len, NameBuff, IOSIZE - 20 - len);
  1040.  
  1041.         len = STRLEN(IObuff);
  1042.         IObuff[len++] = '"';
  1043.         /*
  1044.          * try to put the "line" strings in column 40
  1045.          */
  1046.         do
  1047.         {
  1048.             IObuff[len++] = ' ';
  1049.         } while (len < 40 && len < IOSIZE - 18);
  1050.         sprintf((char *)IObuff + len, "line %ld",
  1051.                 buf == curbuf ? curwin->w_cursor.lnum :
  1052.                                 (long)buflist_findlnum(buf));
  1053.         msg_outtrans(IObuff);
  1054.         flushbuf();            /* output one line at a time */
  1055.         mch_breakcheck();
  1056.     }
  1057. }
  1058.  
  1059. /*
  1060.  * get file name and line number for file 'fnum'
  1061.  * used by DoOneCmd() for translating '%' and '#'
  1062.  * return FAIL if not found, OK for success
  1063.  */
  1064.     int
  1065. buflist_name_nr(fnum, fname, lnum)
  1066.     int            fnum;
  1067.     char_u        **fname;
  1068.     linenr_t    *lnum;
  1069. {
  1070.     BUF            *buf;
  1071.  
  1072.     buf = buflist_findnr(fnum);
  1073.     if (buf == NULL || buf->b_filename == NULL)
  1074.         return FAIL;
  1075.  
  1076.     if (did_cd)
  1077.         *fname = buf->b_filename;
  1078.     else
  1079.         *fname = buf->b_sfilename;
  1080.     *lnum = buflist_findlnum(buf);
  1081.  
  1082.     return OK;
  1083. }
  1084.  
  1085. /*
  1086.  * Set the current file name to 's', short file name to 'ss'.
  1087.  * The file name with the full path is also remembered, for when :cd is used.
  1088.  * Returns FAIL for failure (file name already in use by other buffer)
  1089.  *         OK otherwise.
  1090.  */
  1091.     int
  1092. setfname(fname, sfname, message)
  1093.     char_u *fname, *sfname;
  1094.     int        message;
  1095. {
  1096.     BUF        *buf;
  1097.  
  1098.     if (fname == NULL || *fname == NUL)
  1099.     {
  1100.         vim_free(curbuf->b_filename);
  1101.         vim_free(curbuf->b_sfilename);
  1102.         curbuf->b_filename = NULL;
  1103.         curbuf->b_sfilename = NULL;
  1104.     }
  1105.     else
  1106.     {
  1107.         fname_expand(&fname, &sfname);
  1108. #ifdef USE_FNAME_CASE
  1109. # ifdef USE_LONG_FNAME
  1110.         if (USE_LONG_FNAME)
  1111. # endif
  1112.             fname_case(sfname);        /* set correct case for short filename */
  1113. #endif
  1114.         /*
  1115.          * if the file name is already used in another buffer:
  1116.          * - if the buffer is loaded, fail
  1117.          * - if the buffer is not loaded, delete it from the list
  1118.          */
  1119.         buf = buflist_findname(fname);
  1120.         if (buf != NULL && buf != curbuf)
  1121.         {
  1122.             if (buf->b_ml.ml_mfp != NULL)        /* it's loaded, fail */
  1123.             {
  1124.                 if (message)
  1125.                     EMSG("Buffer with this name already exists");
  1126.                 return FAIL;
  1127.             }
  1128.             close_buffer(NULL, buf, TRUE, TRUE);    /* delete from the list */
  1129.         }
  1130.         fname = strsave(fname);
  1131.         sfname = strsave(sfname);
  1132.         if (fname == NULL || sfname == NULL)
  1133.         {
  1134.             vim_free(sfname);
  1135.             vim_free(fname);
  1136.             return FAIL;
  1137.         }
  1138.         vim_free(curbuf->b_filename);
  1139.         vim_free(curbuf->b_sfilename);
  1140.         curbuf->b_filename = fname;
  1141.         curbuf->b_sfilename = sfname;
  1142.     }
  1143.     if (did_cd)
  1144.         curbuf->b_xfilename = curbuf->b_filename;
  1145.     else
  1146.         curbuf->b_xfilename = curbuf->b_sfilename;
  1147.  
  1148. #ifndef SHORT_FNAME
  1149.     curbuf->b_shortname = FALSE;
  1150. #endif
  1151.     /*
  1152.      * If the file name changed, also change the name of the swapfile
  1153.      */
  1154.     if (curbuf->b_ml.ml_mfp != NULL)
  1155.         ml_setname();
  1156.  
  1157.     check_arg_idx();            /* check file name for arg list */
  1158.     maketitle();                /* set window title */
  1159.     status_redraw_all();        /* status lines need to be redrawn */
  1160.     fmarks_check_names(curbuf);    /* check named file marks */
  1161.     ml_timestamp(curbuf);        /* reset timestamp */
  1162.     return OK;
  1163. }
  1164.  
  1165. /*
  1166.  * set alternate file name for current window
  1167.  *
  1168.  * used by dowrite() and do_ecmd()
  1169.  */
  1170.     void
  1171. setaltfname(fname, sfname, lnum)
  1172.     char_u        *fname;
  1173.     char_u        *sfname;
  1174.     linenr_t    lnum;
  1175. {
  1176.     BUF        *buf;
  1177.  
  1178.     buf = buflist_new(fname, sfname, lnum, FALSE);
  1179.     if (buf != NULL)
  1180.         curwin->w_alt_fnum = buf->b_fnum;
  1181. }
  1182.  
  1183. /*
  1184.  * add a file name to the buflist and return its number
  1185.  *
  1186.  * used by qf_init(), main() and doarglist()
  1187.  */
  1188.     int
  1189. buflist_add(fname)
  1190.     char_u        *fname;
  1191. {
  1192.     BUF        *buf;
  1193.  
  1194.     buf = buflist_new(fname, NULL, (linenr_t)0, FALSE);
  1195.     if (buf != NULL)
  1196.         return buf->b_fnum;
  1197.     return 0;
  1198. }
  1199.  
  1200. /*
  1201.  * set alternate lnum for current window
  1202.  */
  1203.     void
  1204. buflist_altlnum()
  1205. {
  1206.     buflist_setlnum(curbuf, curwin->w_cursor.lnum);
  1207. }
  1208.  
  1209. /*
  1210.  * return nonzero if 'fname' is not the same file as current file
  1211.  * fname must have a full path (expanded by FullName)
  1212.  */
  1213.     int
  1214. otherfile(fname)
  1215.     char_u    *fname;
  1216. {                                    /* no name is different */
  1217.     if (fname == NULL || *fname == NUL || curbuf->b_filename == NULL)
  1218.         return TRUE;
  1219.     return fnamecmp(fname, curbuf->b_filename);
  1220. }
  1221.  
  1222.     void
  1223. fileinfo(fullname, shorthelp, dont_truncate)
  1224.     int fullname;
  1225.     int shorthelp;
  1226.     int    dont_truncate;
  1227. {
  1228.     char_u        *name;
  1229.     int            n;
  1230.     char_u        *p;
  1231.     char_u        *buffer;
  1232.  
  1233.     buffer = alloc(IOSIZE);
  1234.     if (buffer == NULL)
  1235.         return;
  1236.  
  1237.     if (fullname > 1)        /* 2 CTRL-G: include buffer number */
  1238.     {
  1239.         sprintf((char *)buffer, "buf %d: ", curbuf->b_fnum);
  1240.         p = buffer + STRLEN(buffer);
  1241.     }
  1242.     else
  1243.         p = buffer;
  1244.  
  1245.     *p++ = '"';
  1246.     if (curbuf->b_filename == NULL)
  1247.         STRCPY(p, "No File");
  1248.     else
  1249.     {
  1250.         if (!fullname && curbuf->b_sfilename != NULL)
  1251.             name = curbuf->b_sfilename;
  1252.         else
  1253.             name = curbuf->b_filename;
  1254.         home_replace(shorthelp ? curbuf : NULL, name, p,
  1255.                                                 (int)(IOSIZE - (p - buffer)));
  1256.     }
  1257.  
  1258.     sprintf((char *)buffer + STRLEN(buffer),
  1259.             "\"%s%s%s%s",
  1260.             curbuf->b_changed ? (shortmess(SHM_MOD) ?
  1261.                                                 " [+]" : " [Modified]") : " ",
  1262.             curbuf->b_notedited ? "[Not edited]" : "",
  1263.             curbuf->b_p_ro ? (shortmess(SHM_RO) ? "[RO]" : "[readonly]") : "",
  1264.             (curbuf->b_changed || curbuf->b_notedited || curbuf->b_p_ro) ?
  1265.                                                                     " " : "");
  1266.     n = (int)(((long)curwin->w_cursor.lnum * 100L) /
  1267.                                             (long)curbuf->b_ml.ml_line_count);
  1268.     if (curbuf->b_ml.ml_flags & ML_EMPTY)
  1269.     {
  1270.         STRCPY(buffer + STRLEN(buffer), no_lines_msg);
  1271.     }
  1272.     else if (p_ru)
  1273.     {
  1274.         /* Current line and column are already on the screen -- webb */
  1275.         sprintf((char *)buffer + STRLEN(buffer),
  1276.             "%ld line%s --%d%%--",
  1277.             (long)curbuf->b_ml.ml_line_count,
  1278.             plural((long)curbuf->b_ml.ml_line_count),
  1279.             n);
  1280.     }
  1281.     else
  1282.     {
  1283.         sprintf((char *)buffer + STRLEN(buffer),
  1284.             "line %ld of %ld --%d%%-- col ",
  1285.             (long)curwin->w_cursor.lnum,
  1286.             (long)curbuf->b_ml.ml_line_count,
  1287.             n);
  1288.         col_print(buffer + STRLEN(buffer),
  1289.                    (int)curwin->w_cursor.col + 1, (int)curwin->w_virtcol + 1);
  1290.     }
  1291.  
  1292.     append_arg_number(buffer, !shortmess(SHM_FILE));
  1293.  
  1294.     if (dont_truncate)
  1295.         msg(buffer);
  1296.     else
  1297.         msg_trunc(buffer);
  1298.  
  1299.     vim_free(buffer);
  1300. }
  1301.  
  1302. /*
  1303.  * Give some info about the position of the cursor (for "g CTRL-G").
  1304.  */
  1305.     void
  1306. cursor_pos_info()
  1307. {
  1308.     char_u        *p;
  1309.     char_u        buf1[20];
  1310.     char_u        buf2[20];
  1311.     linenr_t    lnum;
  1312.     long        char_count = 0;
  1313.     long        char_count_cursor = 0;
  1314.     int        eol_size;
  1315.  
  1316.     /*
  1317.      * Compute the length of the file in characters.
  1318.      */
  1319.     if (curbuf->b_ml.ml_flags & ML_EMPTY)
  1320.     {
  1321.         MSG(no_lines_msg);
  1322.     }
  1323.     else
  1324.     {
  1325.         if (curbuf->b_p_tx)
  1326.             eol_size = 2;
  1327.         else
  1328.             eol_size = 1;
  1329.         for (lnum = 1; lnum <= curbuf->b_ml.ml_line_count; ++lnum)
  1330.         {
  1331.             if (lnum == curwin->w_cursor.lnum)
  1332.                 char_count_cursor = char_count + curwin->w_cursor.col + 1;
  1333.             char_count += STRLEN(ml_get(lnum)) + eol_size;
  1334.         }
  1335.         if (!curbuf->b_p_eol && curbuf->b_p_bin)
  1336.             char_count -= eol_size;
  1337.  
  1338.         p = ml_get_curline();
  1339.         col_print(buf1, (int)curwin->w_cursor.col + 1, (int)curwin->w_virtcol + 1);
  1340.         col_print(buf2, (int)STRLEN(p), linetabsize(p));
  1341.  
  1342.         sprintf((char *)IObuff, "Col %s of %s; Line %ld of %ld; Char %ld of %ld",
  1343.                 (char *)buf1, (char *)buf2,
  1344.                 (long)curwin->w_cursor.lnum, (long)curbuf->b_ml.ml_line_count,
  1345.                 char_count_cursor, char_count);
  1346.         msg(IObuff);
  1347.     }
  1348. }
  1349.  
  1350.     void
  1351. col_print(buf, col, vcol)
  1352.     char_u    *buf;
  1353.     int        col;
  1354.     int        vcol;
  1355. {
  1356.     if (col == vcol)
  1357.         sprintf((char *)buf, "%d", col);
  1358.     else
  1359.         sprintf((char *)buf, "%d-%d", col, vcol);
  1360. }
  1361.  
  1362. /*
  1363.  * put filename in title bar of window and in icon title
  1364.  */
  1365.  
  1366. static char_u *lasttitle = NULL;
  1367. static char_u *lasticon = NULL;
  1368.  
  1369.     void
  1370. maketitle()
  1371. {
  1372.     char_u        *t_name;
  1373.     char_u        *i_name;
  1374.  
  1375.     if (curbuf->b_filename == NULL)
  1376.     {
  1377.         t_name = (char_u *)"";
  1378.         i_name = (char_u *)"No File";
  1379.     }
  1380.     else
  1381.     {
  1382.         home_replace(curbuf, curbuf->b_filename, IObuff, IOSIZE);
  1383.         append_arg_number(IObuff, FALSE);
  1384.         t_name = IObuff;
  1385.         i_name = gettail(curbuf->b_filename);    /* use filename only for icon */
  1386.     }
  1387.  
  1388.     vim_free(lasttitle);
  1389.     if (p_title && (lasttitle = alloc((unsigned)(strsize(t_name) + 7))) != NULL)
  1390.     {
  1391.         STRCPY(lasttitle, "VIM - ");
  1392.         while (*t_name)
  1393.             STRCAT(lasttitle, transchar(*t_name++));
  1394.     }
  1395.     else
  1396.         lasttitle = NULL;
  1397.  
  1398.     vim_free(lasticon);
  1399.     if (p_icon && (lasticon = alloc((unsigned)(strsize(i_name) + 1))) != NULL)
  1400.     {
  1401.         *lasticon = NUL;
  1402.         while (*i_name)
  1403.             STRCAT(lasticon, transchar(*i_name++));
  1404.     }
  1405.     else
  1406.         lasticon = NULL;
  1407.  
  1408.     resettitle();
  1409. }
  1410.  
  1411. /*
  1412.  * Append (file 2 of 8) to 'buf'.
  1413.  */
  1414.     static void
  1415. append_arg_number(buf, add_file)
  1416.     char_u    *buf;
  1417.     int        add_file;        /* Add "file" before the arg number */
  1418. {
  1419.     if (arg_count <= 1)        /* nothing to do */
  1420.         return;
  1421.  
  1422.     buf += STRLEN(buf);        /* go to the end of the buffer */
  1423.     *buf++ = ' ';
  1424.     *buf++ = '(';
  1425.     if (add_file)
  1426.     {
  1427.         STRCPY(buf, "file ");
  1428.         buf += 5;
  1429.     }
  1430.     sprintf((char *)buf, curwin->w_arg_idx_invalid ? "(%d) of %d)" :
  1431.                                  "%d of %d)", curwin->w_arg_idx + 1, arg_count);
  1432. }
  1433.  
  1434. /*
  1435.  * Put current window title back (used after calling a shell)
  1436.  */
  1437.     void
  1438. resettitle()
  1439. {
  1440.     mch_settitle(lasttitle, lasticon);
  1441. }
  1442.  
  1443. /*
  1444.  * If fname is not a full path, make it a full path
  1445.  */
  1446.     char_u    *
  1447. fix_fname(fname)
  1448.     char_u    *fname;
  1449. {
  1450.     if (fname != NameBuff)            /* if not already expanded */
  1451.     {
  1452.         if (!isFullName(fname))
  1453.         {
  1454.             (void)FullName(fname, NameBuff, MAXPATHL, FALSE);
  1455.             fname = NameBuff;
  1456.         }
  1457. #ifdef USE_FNAME_CASE
  1458.         else
  1459. # ifdef USE_LONG_FNAME
  1460.             if (USE_LONG_FNAME)
  1461. # endif
  1462.         {
  1463.             STRNCPY(NameBuff, fname, MAXPATHL);    /* make copy, it may change */
  1464.             fname = NameBuff;
  1465.             fname_case(fname);            /* set correct case for filename */
  1466.         }
  1467. #endif
  1468.     }
  1469.     return fname;
  1470. }
  1471.  
  1472. /*
  1473.  * make fname a full file name, set sfname to fname if not NULL
  1474.  */
  1475.     void
  1476. fname_expand(fname, sfname)
  1477.     char_u        **fname;
  1478.     char_u        **sfname;
  1479. {
  1480.     if (*fname == NULL)            /* if no file name given, nothing to do */
  1481.         return;
  1482.     if (*sfname == NULL)        /* if no short file name given, use fname */
  1483.         *sfname = *fname;
  1484.     *fname = fix_fname(*fname);    /* expand to full path */
  1485. }
  1486.  
  1487. /*
  1488.  * do_arg_all: open up to 'count' windows, one for each argument
  1489.  */
  1490.     void
  1491. do_arg_all(count)
  1492.     int count;
  1493. {
  1494.     int        i;
  1495.  
  1496.     if (arg_count <= 1)
  1497.     {
  1498.         /* Don't give this obvious error message. We don't want it when the
  1499.          * ":all" command is in the .vimrc. */
  1500.         /* EMSG("Argument list contains less than 2 files"); */
  1501.         return;
  1502.     }
  1503.     /*
  1504.      * 1. close all but first window
  1505.      * 2. make the desired number of windows
  1506.      * 3. start editing in the windows
  1507.      */
  1508.     setpcmark();
  1509.     close_others(FALSE);
  1510.     curwin->w_arg_idx = 0;
  1511.     if (count > arg_count || count <= 0)
  1512.         count = arg_count;
  1513.     count = make_windows(count);
  1514.     for (i = 0; i < count; ++i)
  1515.     {
  1516.                                                 /* edit file i */
  1517.         (void)do_ecmd(0, arg_files[i], NULL, NULL, TRUE, (linenr_t)1, FALSE);
  1518.         curwin->w_arg_idx = i;
  1519.         if (i == arg_count - 1)
  1520.             arg_had_last = TRUE;
  1521.         if (curwin->w_next == NULL)                /* just checking */
  1522.             break;
  1523.         win_enter(curwin->w_next, FALSE);
  1524.     }
  1525.     win_enter(firstwin, FALSE);                    /* back to first window */
  1526. }
  1527.  
  1528. /*
  1529.  * do_arg_all: open a window for each buffer
  1530.  *
  1531.  * 'count' is the maximum number of windows to open.
  1532.  * when 'all' is TRUE, also load inactive buffers
  1533.  */
  1534.     void
  1535. do_buffer_all(count, all)
  1536.     int        count;
  1537.     int        all;
  1538. {
  1539.     int        buf_count;
  1540.     BUF        *buf;
  1541.     int        i;
  1542.  
  1543. /*
  1544.  * count number of desired windows
  1545.  */
  1546.     buf_count = 0; 
  1547.     for (buf = firstbuf; buf != NULL; buf = buf->b_next)
  1548.         if (all || buf->b_ml.ml_mfp != NULL)
  1549.             ++buf_count;
  1550.  
  1551.     if (buf_count == 0)                /* Cannot happen? */
  1552.     {
  1553.         EMSG("No relevant entries in buffer list");
  1554.         return;
  1555.     }
  1556.  
  1557.     /*
  1558.      * 1. close all but first window
  1559.      * 2. make the desired number of windows
  1560.      * 3. stuff commands to fill the windows
  1561.      */
  1562.     close_others(FALSE);
  1563.     curwin->w_arg_idx = 0;
  1564.     if (buf_count > count)
  1565.         buf_count = count;
  1566.     buf_count = make_windows(buf_count);
  1567.     buf = firstbuf;
  1568.     for (i = 0; i < buf_count; ++i)
  1569.     {
  1570.         for ( ; buf != NULL; buf = buf->b_next)
  1571.             if (all || buf->b_ml.ml_mfp != NULL)
  1572.                 break;
  1573.         if (buf == NULL)            /* Cannot happen? */
  1574.             break;
  1575.         if (i != 0)
  1576.             stuffReadbuff((char_u *)"\n\027\027:");    /* CTRL-W CTRL-W */
  1577.         stuffReadbuff((char_u *)":buf ");            /* edit Nth buffer */
  1578.         stuffnumReadbuff((long)buf->b_fnum);
  1579.         buf = buf->b_next;
  1580.     }
  1581.     stuffReadbuff((char_u *)"\n100\027k");        /* back to first window */
  1582. }
  1583.  
  1584. /*
  1585.  * do_modelines() - process mode lines for the current file
  1586.  *
  1587.  * Returns immediately if the "ml" option isn't set.
  1588.  */
  1589. static int     chk_modeline __ARGS((linenr_t));
  1590.  
  1591.     void
  1592. do_modelines()
  1593. {
  1594.     linenr_t        lnum;
  1595.     int             nmlines;
  1596.  
  1597.     if (!curbuf->b_p_ml || (nmlines = (int)p_mls) == 0)
  1598.         return;
  1599.  
  1600.     for (lnum = 1; lnum <= curbuf->b_ml.ml_line_count && lnum <= nmlines;
  1601.                                                                        ++lnum)
  1602.         if (chk_modeline(lnum) == FAIL)
  1603.             nmlines = 0;
  1604.  
  1605.     for (lnum = curbuf->b_ml.ml_line_count; lnum > 0 && lnum > nmlines &&
  1606.                           lnum > curbuf->b_ml.ml_line_count - nmlines; --lnum)
  1607.         if (chk_modeline(lnum) == FAIL)
  1608.             nmlines = 0;
  1609. }
  1610.  
  1611. /*
  1612.  * chk_modeline() - check a single line for a mode string
  1613.  * Return FAIL if an error encountered.
  1614.  */
  1615.     static int
  1616. chk_modeline(lnum)
  1617.     linenr_t lnum;
  1618. {
  1619.     register char_u    *s;
  1620.     register char_u    *e;
  1621.     char_u            *linecopy;            /* local copy of any modeline found */
  1622.     int                prev;
  1623.     int                end;
  1624.     int                retval = OK;
  1625.     char_u            *save_sourcing_name;
  1626.  
  1627.     prev = -1;
  1628.     for (s = ml_get(lnum); *s != NUL; ++s)
  1629.     {
  1630.         if (prev == -1 || vim_isspace(prev))
  1631.         {
  1632.             if ((prev != -1 && STRNCMP(s, "ex:", (size_t)3) == 0) ||
  1633.                                 STRNCMP(s, "vi:", (size_t)3) == 0 ||
  1634.                                STRNCMP(s, "vim:", (size_t)4) == 0)
  1635.                 break;
  1636.         }
  1637.         prev = *s;
  1638.     }
  1639.  
  1640.     if (*s)
  1641.     {
  1642.         do                                /* skip over "ex:", "vi:" or "vim:" */
  1643.             ++s;
  1644.         while (s[-1] != ':');
  1645.  
  1646.         s = linecopy = strsave(s);        /* copy the line, it will change */
  1647.         if (linecopy == NULL)
  1648.             return FAIL;
  1649.  
  1650.         sourcing_lnum = lnum;            /* prepare for emsg() */
  1651.         save_sourcing_name = sourcing_name;
  1652.         sourcing_name = (char_u *)"modelines";
  1653.  
  1654.         end = FALSE;
  1655.         while (end == FALSE)
  1656.         {
  1657.             s = skipwhite(s);
  1658.             if (*s == NUL)
  1659.                 break;
  1660.  
  1661.             /*
  1662.              * Find end of set command: ':' or end of line.
  1663.              */
  1664.             for (e = s; (*e != ':' || *(e - 1) == '\\') && *e != NUL; ++e)
  1665.                 ;
  1666.             if (*e == NUL)
  1667.                 end = TRUE;
  1668.  
  1669.             /*
  1670.              * If there is a "set" command, require a terminating ':' and
  1671.              * ignore the stuff after the ':'.
  1672.              * "vi:set opt opt opt: foo" -- foo not interpreted
  1673.              * "vi:opt opt opt: foo" -- foo interpreted
  1674.              */
  1675.             if (STRNCMP(s, "set ", (size_t)4) == 0)
  1676.             {
  1677.                 if (*e != ':')            /* no terminating ':'? */
  1678.                     break;
  1679.                 end = TRUE;
  1680.                 s += 4;
  1681.             }
  1682.  
  1683.             *e = NUL;                    /* truncate the set command */
  1684.             if (do_set(s) == FAIL)        /* stop if error found */
  1685.             {
  1686.                 retval = FAIL;
  1687.                 break;
  1688.             }
  1689.             s = e + 1;                    /* advance to next part */
  1690.         }
  1691.  
  1692.         sourcing_lnum = 0;
  1693.         sourcing_name = save_sourcing_name;
  1694.  
  1695.         vim_free(linecopy);
  1696.     }
  1697.     return retval;
  1698. }
  1699.